<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>文件管理 - 信院数字人后台</title>
    <script src="https://cdn.tailwindcss.com"></script>
    <link href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css" rel="stylesheet">
    <style>
        :root{--color-primary:#003366;--color-danger:#d7000f;--color-border:#d0d0d0;--color-row-hover:#f5f7fa;}
        body{font-family:"Helvetica Neue",Helvetica,"PingFang SC","Hiragino Sans GB","Microsoft YaHei",sans-serif;background:#f3f4f6;font-size:14px;}
        .sidebar{width:240px;background:#001529;color:#c7d0d9;display:flex;flex-direction:column;}
        .sidebar .logo{height:64px;display:flex;align-items:center;justify-content:center;font-size:18px;font-weight:600;background:#002140;color:#fff;padding:0 16px;}
        .sidebar .logo img{width:40px;height:40px;border-radius:50%;margin-right:12px;object-fit:contain;background:#fff;padding:2px;}
        .sidebar .menu a{display:block;padding:12px 24px;font-size:14px;transition:background .2s;}
        .sidebar .menu a:hover,.sidebar .menu a.active{background:#1890ff;color:#fff;}
        .topbar{height:64px;background:#fff;border-bottom:1px solid var(--color-border);padding:0 24px;display:flex;align-items:center;justify-content:space-between;}
        .btn{display:inline-flex;align-items:center;justify-content:center;padding:6px 16px;font-size:14px;border:1px solid var(--color-border);background:#fff;cursor:pointer;transition:all .2s;border-radius:4px;}
        .btn-primary{background:var(--color-primary);color:#fff;border-color:var(--color-primary);}
        .btn-primary:hover{background:#004080;}
        .btn-danger{color:var(--color-danger);border-color:var(--color-danger);}
        .btn-danger:hover{background:var(--color-danger);color:#fff;}
        .data-table{width:100%;border-collapse:collapse;border-spacing:0;empty-cells:show;border:1px solid var(--color-border);}
        .data-table thead{background-color:#f5f7fa;color:#333;}
        .data-table th,.data-table td{padding:12px 16px;border-bottom:1px solid var(--color-border);border-right:1px solid var(--color-border);text-align:left;word-break:break-all;line-height:1.4;vertical-align:middle;}
        .data-table th:last-child,.data-table td:last-child{border-right:none;}
        .data-table tr:hover{background-color:var(--color-row-hover);}
        .data-table th.id-col{width:80px;}.data-table th.file-id-col{width:180px;}.data-table th.name-col{width:200px;}
        .data-table th.time-col{width:160px;}.data-table th.action-col{width:100px;text-align:center;}
        .data-table td.action-col{text-align:center;}
        .action-btn{display:inline-block;width:28px;height:28px;line-height:28px;text-align:center;border-radius:4px;margin:0 4px;cursor:pointer;transition:all .2s;color:#666;border:1px solid transparent;}
        .action-btn:hover{background-color:#f0f0f0;border-color:#ddd;}
        .action-btn.edit{color:#1890ff;}.action-btn.edit:hover{background-color:#e6f7ff;border-color:#bae7ff;}
        .action-btn.delete{color:#ff4d4f;}.action-btn.delete:hover{background-color:#fff2f0;border-color:#ffccc7;}
        .action-btn.download{color:#52c41a;}.action-btn.download:hover{background-color:#f6ffed;border-color:#b7eb8f;}
        .file-icon{display:inline-block;width:24px;height:24px;line-height:24px;text-align:center;color:#666;}
        .modal-mask{position:fixed;inset:0;background:rgba(0,0,0,.45);display:flex;align-items:center;justify-content:center;z-index:999;opacity:0;pointer-events:none;transition:opacity .3s;}
        .modal-mask.show{opacity:1;pointer-events:auto;}
        .modal-box{background:#fff;width:640px;max-width:90vw;max-height:90vh;overflow:auto;display:flex;flex-direction:column;border-radius:6px;box-shadow:0 4px 12px rgba(0,0,0,0.15);}
        .modal-header{padding:16px 24px;border-bottom:1px solid var(--color-border);font-size:16px;font-weight:600;}
        .modal-footer{padding:12px 24px;border-top:1px solid var(--color-border);text-align:right;}
        .form-input{width:100%;padding:7px 11px;border:1px solid var(--color-border);font-size:14px;transition:border-color .2s;border-radius:4px;}
        .form-input:focus{border-color:var(--color-primary);outline:none;box-shadow:0 0 0 2px rgba(0,51,102,.2);}
        .pagination{font-size:14px;display:flex;align-items:center;gap:8px;}
        .pagination .btn:disabled{opacity:.6;cursor:not-allowed;}
        main {
            padding-bottom: 60px !important;
        }
        #page {
            position: fixed;
            bottom: 0;
            left: 0;
            right: 0;
            background: white;
            z-index: 10;
            border-top: 1px solid var(--color-border);
            box-shadow: 0 -2px 8px rgba(0,0,0,0.05);
        }
    </style>
</head>
<body class="flex h-screen overflow-hidden">
<aside class="sidebar">
    <div class="logo"><img src="/logo/logo.jpg" alt="logo" onerror="this.src='https://picsum.photos/40/40?random=logo';this.style.background='#fff';">信院数字人后台</div>
    <nav class="menu flex-1 pt-4">
        <a href="/admin/usersManage.html"><i class="fa fa-user-o mr-2"></i>用户管理</a>
        <a href="/admin/postsManage.html"><i class="fa fa-comments-o mr-2"></i>言论详情</a>
        <a href="/admin/imagesManage.html"><i class="fa fa-image mr-2"></i>图片管理</a>
        <a href="/admin/filesManage.html" class="active"><i class="fa fa-file-o mr-2"></i>文件管理</a>
    </nav>
</aside>

<section class="flex-1 flex flex-col">
    <header class="topbar">
        <div class="text-base font-medium">文件管理</div>
        <div class="flex items-center gap-4"><span class="text-sm">管理员</span><img src="/logo/guanliyuan.png" class="w-8 h-8 rounded-full"></div>
    </header>

    <main class="flex-1 overflow-y-auto p-6">
        <div class="bg-white border border-gray-200 rounded px-4 py-3 mb-4 flex items-center justify-between">
            <div class="flex items-center gap-4">
                <input id="keyword" type="text" placeholder="请输入文件名或文件ID" class="form-input w-64">
                <button id="searchBtn" class="btn btn-primary">查询</button>
                <button id="resetBtn" class="btn">重置</button>
            </div>
            <button id="addBtn" class="btn btn-primary" onclick="showAddModal()"><i class="fa fa-plus mr-1"></i>上传文件</button>
        </div>

        <div class="bg-white rounded overflow-x-auto shadow-sm">
            <table class="data-table min-w-[940px]">
                <thead>
                <tr>
                    <th class="id-col">ID</th>
                    <th class="file-id-col">文件ID</th>
                    <th class="name-col">文件名</th>
                    <th class="time-col">上传时间</th>
                    <th class="time-col">更新时间</th>
                    <th class="action-col">操作</th>
                </tr>
                </thead>
                <tbody id="list"></tbody>
            </table>
        </div>
    </main>

    <div id="page" class="px-4 py-3 flex items-center justify-between text-sm text-gray-600">
        <div>共 <span id="total">0</span> 条</div>
        <div class="pagination">
            <button id="prev" class="btn">上一页</button>
            <span>第 <span id="curr">1</span> 页 / 共 <span id="pages">1</span> 页</span>
            <button id="next" class="btn">下一页</button>
        </div>
    </div>
</section>

<!-- 上传文件模态框 -->
<div id="formModal" class="modal-mask"><div class="modal-box">
    <div class="modal-header"><span id="modalTitle">上传文件</span><button class="btn btn-sm ml-auto" onclick="hideFormModal()"><i class="fa fa-times"></i></button></div>
    <div id="form" class="px-6 py-4 space-y-4">
        <div>
            <label class="block text-sm font-medium mb-1">选择文件 <span class="text-red-600">*</span></label>
            <div id="uploadBox" class="border border-dashed border-gray-400 rounded p-8 text-center cursor-pointer">
                <input type="file" id="fileInput" class="hidden">
                <i class="fa fa-cloud-upload text-4xl text-gray-400 mb-2"></i>
                <p class="text-gray-500">点击或拖拽文件到此处上传</p>
                <p class="text-xs text-gray-400 mt-1">支持所有类型文件</p>
            </div>
            <div id="fileInfo" class="mt-2 hidden">
                <div class="flex items-center justify-between p-2 bg-gray-50 rounded">
                    <span id="fileName" class="text-sm"></span>
                    <span id="fileSize" class="text-xs text-gray-500"></span>
                </div>
            </div>
        </div>
    </div>
    <div class="modal-footer">
        <button type="button" class="btn" onclick="hideFormModal()">取消</button>
        <button type="button" id="uploadBtn" class="btn btn-primary">上传</button>
    </div>
</div></div>

<!-- 删除确认框 -->
<div id="delModal" class="modal-mask"><div class="modal-box max-w-sm">
    <div class="modal-header">删除确认</div>
    <div class="p-6 text-center text-sm text-gray-700">此操作不可撤销，确定删除？</div>
    <div class="modal-footer">
        <button class="btn" onclick="hideDelModal()">取消</button>
        <button id="delConfirm" class="btn btn-danger">删除</button>
    </div>
</div></div>

<script>
    const $ = q => document.querySelector(q);
    const modalForm = $('#formModal'), modalDel = $('#delModal');
    let currPage = 1, pageSize = 6, delId = 0, totalPages = 1;

    async function request(url, option = {}) {
        const headers = { 'Content-Type': 'application/json', ...option.headers };
        const body = option.body && typeof option.body === 'object' ? JSON.stringify(option.body) : option.body;
        const res = await fetch(url, { ...option, headers, body, credentials: 'include' });
        if (!res.ok) throw new Error(await res.text());
        const ct = res.headers.get('content-type');
        return ct && ct.includes('application/json') ? res.json() : res.text();
    }

    function getFileIcon(filename) {
        const ext = filename.split('.').pop().toLowerCase();
        const iconMap = {
            pdf: 'fa-file-pdf-o',
            doc: 'fa-file-word-o', docx: 'fa-file-word-o',
            xls: 'fa-file-excel-o', xlsx: 'fa-file-excel-o',
            ppt: 'fa-file-powerpoint-o', pptx: 'fa-file-powerpoint-o',
            txt: 'fa-file-text-o',
            zip: 'fa-file-zip-o', rar: 'fa-file-zip-o', '7z': 'fa-file-zip-o'
        };
        return iconMap[ext] || 'fa-file-o';
    }

    function formatFileSize(bytes) {
        if (bytes === 0) return '0 B';
        const k = 1024;
        const sizes = ['B', 'KB', 'MB', 'GB'];
        const i = Math.floor(Math.log(bytes) / Math.log(k));
        return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
    }

    async function loadTable() {
        const kw = $('#keyword').value.trim();
        const params = new URLSearchParams({ pageNum: currPage, pageSize, keyword: kw });
        try {
            const res = await request('/api/admin/files?' + params);
            const list = res.records || [], total = res.total || 0;
            totalPages = Math.max(1, Math.ceil(total / pageSize));
            let html = '';
            list.forEach(r => {
                html += `<tr>
                    <td class="id-col">${r.id}</td>
                    <td class="file-id-col">${r.fileId}</td>
                    <td class="name-col">
                        <i class="fa ${getFileIcon(r.fileName)} file-icon mr-2"></i>
                        ${r.fileName}
                    </td>
                    <td class="time-col">${r.createTime || '-'}</td>
                    <td class="time-col">${r.updateTime || '-'}</td>
                    <td class="action-col">
                        <span class="action-btn download" title="下载" onclick="downloadFile('${r.fileId}')"><i class="fa fa-download"></i></span>
                        <span class="action-btn delete" title="删除" onclick="delRow('${r.fileId}')"><i class="fa fa-trash-o"></i></span>
                    </td>
                </tr>`;
            });
            $('#list').innerHTML = html || '<tr><td colspan="6" class="text-center text-gray-400 py-8">暂无数据</td></tr>';
            $('#total').textContent = total;
            $('#curr').textContent = currPage;
            $('#pages').textContent = totalPages;
            $('#prev').disabled = currPage === 1;
            $('#next').disabled = currPage === totalPages;
        } catch (e) { alert('加载表格失败：' + e.message); }
    }

    $('#prev').onclick = () => {
        if (currPage > 1) { currPage--; loadTable(); }
    };
    $('#next').onclick = () => {
        if (currPage < totalPages) { currPage++; loadTable(); }
        else { alert('已经是最后一页啦！'); }
    };

    function showAddModal() {
        $('#fileInput').value = '';
        $('#fileInfo').classList.add('hidden');
        modalForm.classList.add('show');
    }

    function hideFormModal() { modalForm.classList.remove('show'); }
    function hideDelModal() { modalDel.classList.remove('show'); }

    $('#uploadBox').onclick = () => $('#fileInput').click();

    $('#fileInput').onchange = (e) => {
        const file = e.target.files[0];
        if (!file) {
            $('#fileInfo').classList.add('hidden');
            return;
        }
        $('#fileName').textContent = file.name;
        $('#fileSize').textContent = formatFileSize(file.size);
        $('#fileInfo').classList.remove('hidden');
    };

    $('#uploadBox').ondragover = e => {
        e.preventDefault();
        $('#uploadBox').classList.add('border-primary', 'bg-blue-50');
    };

    $('#uploadBox').ondragleave = () => {
        $('#uploadBox').classList.remove('border-primary', 'bg-blue-50');
    };

    $('#uploadBox').ondrop = e => {
        e.preventDefault();
        $('#uploadBox').classList.remove('border-primary', 'bg-blue-50');
        const file = e.dataTransfer.files[0];
        if (file) {
            $('#fileInput').files = e.dataTransfer.files;
            $('#fileName').textContent = file.name;
            $('#fileSize').textContent = formatFileSize(file.size);
            $('#fileInfo').classList.remove('hidden');
        }
    };

    $('#uploadBtn').onclick = async () => {
        const file = $('#fileInput').files[0];
        if (!file) return alert('请选择要上传的文件');

        try {
            // 显示上传中状态
            const originalText = $('#uploadBtn').innerHTML;
            $('#uploadBtn').innerHTML = '<i class="fa fa-spinner fa-spin mr-1"></i> 上传中...';
            $('#uploadBtn').disabled = true;

            const base64 = await new Promise((resolve, reject) => {
                const reader = new FileReader();
                reader.onload = e => resolve(e.target.result.split(',')[1]);
                reader.onerror = reject;
                reader.readAsDataURL(file);
            });

            // 大文件分片处理（1MB per chunk）
            const chunkSize = 1024 * 1024;
            const totalChunks = Math.ceil(base64.length / chunkSize);
            let currentChunk = 0;

            // 模拟文件分片上传进度
            function uploadNextChunk() {
                return new Promise((resolve, reject) => {
                    if (currentChunk >= totalChunks) {
                        resolve();
                        return;
                    }

                    // 计算当前分片
                    const start = currentChunk * chunkSize;
                    const end = Math.min(start + chunkSize, base64.length);
                    const chunk = base64.substring(start, end);

                    // 模拟分片上传
                    setTimeout(() => {
                        currentChunk++;
                        const progress = Math.floor((currentChunk / totalChunks) * 90);
                        console.log(`上传进度: ${progress}%`);
                        uploadNextChunk().then(resolve).catch(reject);
                    }, 10); // 模拟网络延迟
                });
            }

            // 开始上传分片
            await uploadNextChunk();

            // 发送最终的上传请求
            await request('/api/admin/files', {
                method: 'POST',
                body: {
                    fileName: file.name,
                    fileContent: base64
                }
            });

            hideFormModal();
            loadTable();
            alert('文件上传成功\n文件内容已处理并存储到向量数据库，可在聊天系统中查询文件内容');
        } catch (e) {
            alert('上传失败：' + e.message);
        } finally {
            // 恢复按钮状态
            $('#uploadBtn').innerHTML = '<i class="fa fa-upload mr-1"></i> 上传';
            $('#uploadBtn').disabled = false;
        }
    };

    function downloadFile(fileId) {
        window.location.href = `/api/admin/files/${fileId}/download`;
    }

    function delRow(id) { delId = id; modalDel.classList.add('show'); }
    $('#delConfirm').onclick = async () => {
        try {
            await request(`/api/admin/files/${delId}`, { method: 'DELETE' });
            hideDelModal(); loadTable(); alert('删除成功');
        } catch (e) { alert('删除失败：' + e.message); }
    };

    $('#searchBtn').onclick = () => { currPage = 1; loadTable(); };
    $('#resetBtn').onclick = () => {
        $('#keyword').value = '';
        currPage = 1;
        loadTable();
    };

    window.onload = () => { loadTable(); };
</script>
</body>
</html>
